"""
Database models for the Flask Database demo.
"""
import re
from datetime import datetime

from flask_sqlalchemy import SQLAlchemy

# Initialize SQLAlchemy
db = SQLAlchemy()


class User(db.Model):
    """User model representing a user in the system."""

    # Table name (optional, defaults to class name lowercase)
    __tablename__ = 'users'

    # Columns
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False, index=True)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(128))
    member_since = db.Column(db.DateTime, default=datetime.utcnow)

    # Relationships
    posts = db.relationship('Post', backref='author', lazy='dynamic', cascade='all, delete-orphan')

    def __repr__(self):
        """String representation of the User object."""
        return f'<User {self.username}>'

    def to_dict(self):
        """Convert User object to dictionary."""
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'member_since': self.member_since.isoformat() if self.member_since else None
        }

    @staticmethod
    def validate_username(username):
        """Validate username format."""
        if not username:
            return "Username is required"
        if len(username) < 3 or len(username) > 20:
            return "Username must be between 3 and 20 characters"
        if not re.match("^[A-Za-z0-9_]+$", username):
            return "Username can only contain letters, numbers, and underscores"
        return None

    @staticmethod
    def validate_email(email):
        """Validate email format."""
        if not email:
            return "Email is required"
        if len(email) > 120:
            return "Email is too long"
        if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
            return "Please enter a valid email address"
        return None


class Post(db.Model):
    """Post model representing a blog post."""

    # Table name
    __tablename__ = 'posts'

    # Columns
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    body = db.Column(db.Text, nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)

    # Foreign key to User
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

    def __repr__(self):
        """String representation of the Post object."""
        return f'<Post {self.title}>'

    def to_dict(self):
        """Convert Post object to dictionary."""
        return {
            'id': self.id,
            'title': self.title,
            'body': self.body,
            'timestamp': self.timestamp.isoformat() if self.timestamp else None,
            'author': self.author.to_dict() if self.author else None
        }

    @staticmethod
    def validate_title(title):
        """Validate post title."""
        if not title:
            return "Title is required"
        if len(title) > 100:
            return "Title must be less than 100 characters"
        return None

    @staticmethod
    def validate_body(body):
        """Validate post body."""
        if not body:
            return "Post content is required"
        if len(body) > 1000:
            return "Post content must be less than 1000 characters"
        return None
